﻿using Anotar.LibLog;
using Newbe.TestDirector.Notification.Web.Domain;
using Newbe.TestDirector.Notification.Web.Domain.Impl;
using Newbe.TestDirector.Notification.Web.Entities;
using Quartz;
using System;
using System.Data.Entity;
using System.Linq;

namespace Newbe.TestDirector.Notification.Web.Jobs
{
    [DisallowConcurrentExecution]
    public class TdNotificationJob : IJob, ITdNotificationJob, IMyJob
    {
        private readonly SystemOptions _systemOptions;
        private readonly IHistoryTestDirectorDatabaseStore _historyTestDirectorDatabaseStore;
        private readonly ITestDirectorAccessDbComparer _testDirectorAccessDbComparer;
        private readonly BugDao.Factory _bugDaoFactory;
        private readonly IEfContext _efContext;
        private readonly INotificator _notificator;
        private readonly IDomainEventLogService _domainEventLogService;
        private readonly INotificationJobLogger _notificationJobLogger;

        public TdNotificationJob(SystemOptions systemOptions,
            IHistoryTestDirectorDatabaseStore historyTestDirectorDatabaseStore,
            ITestDirectorAccessDbComparer testDirectorAccessDbComparer,
            BugDao.Factory bugDaoFactory,
            IEfContext efContext,
            INotificator notificator,
            IDomainEventLogService domainEventLogService,
            INotificationJobLogger notificationJobLogger)
        {
            _systemOptions = systemOptions;
            _historyTestDirectorDatabaseStore = historyTestDirectorDatabaseStore;
            _testDirectorAccessDbComparer = testDirectorAccessDbComparer;
            _bugDaoFactory = bugDaoFactory;
            _efContext = efContext;
            _notificator = notificator;
            _domainEventLogService = domainEventLogService;
            _notificationJobLogger = notificationJobLogger;
        }

        [LogToErrorOnException]
        public void Notificat()
        {
            var olddb = _historyTestDirectorDatabaseStore.GetLastest();
            _historyTestDirectorDatabaseStore.AddNew(new TestDirectorAcceessDb
            {
                FilePath = _systemOptions.TestDirectorDatabaseFilePath,
                TimeStamp = DateTimeOffset.UtcNow
            });
            if (olddb == null)
            {
                LogTo.Info("there are no tddbs");
                return;
            }
            var nowdb = _historyTestDirectorDatabaseStore.GetLastest();
            var olddata = _bugDaoFactory(olddb).List().ToArray();
            try
            {
                var logContext = new NotificationJobContext();
                var nowData = _bugDaoFactory(nowdb).List().ToArray();
                var cprResult = _testDirectorAccessDbComparer.Compare(olddata, nowData);
                logContext.ComparedBugChangeResultCollection = cprResult;
                var mailerSenderBookCollection = new MailerSenderBookCollection();
                var mailInfos = _efContext.MailerInfos.ToArray();
                foreach (var scene in _efContext.MailScenes
                    .Include(x => x.MailSceneMailerInfoSource)
                    .Include(x => x.MailSceneMailerInfoSource.MailerInfos)
                    .Include(x => x.ShowColumns)
                    .ToArray())
                {
                    var matchedResult = scene.Match(cprResult);
                    if (matchedResult.Any())
                    {
                        logContext.NotificationMatchedMailerSceneInfos.Add(new NotificationMatchedMailerSceneInfo
                        {
                            MatchedSceneBugChangeResultCollection = matchedResult,
                            MailSceneEntity = scene,
                        });
                        switch (scene.MailSceneMailerInfoSource.MailSceneMailerInfoSourceType)
                        {
                            case MailSceneMailerInfoSourceType.Static:
                                foreach (var mailerInfoEntity in scene.MailSceneMailerInfoSource.MailerInfos)
                                {
                                    mailerSenderBookCollection.Add(mailerInfoEntity, scene, matchedResult);
                                }
                                break;
                            case MailSceneMailerInfoSourceType.TableColumn:
                                var coleName = scene.MailSceneMailerInfoSource.MailerInfoFromColumn.ColumnName;
                                foreach (var mailerInfoColValue in matchedResult.Select(x => x.NowData[coleName]).Distinct())
                                {
                                    var mailerInfoEntity = mailInfos.FirstOrDefault(x =>
                                        x.Name == mailerInfoColValue || x.MailAddress == mailerInfoColValue);
                                    if (mailerInfoEntity != null)
                                    {
                                        mailerSenderBookCollection.Add(mailerInfoEntity, scene, matchedResult);
                                    }
                                    _domainEventLogService.AddDoaminEventLog("发送邮件时，寻找发件人失败", $"尝试使用{coleName}字段对应的值{mailerInfoColValue}从现有的联系人中寻找收件箱。结果无法找到。请在收件人管理中配置相关的收件人。");
                                }
                                break;
                            default:
                                throw new ArgumentOutOfRangeException();
                        }
                    }
                }
                _notificationJobLogger.Add(logContext);
                if (mailerSenderBookCollection.Any())
                {
                    _notificator.Notificat(new NotificatContext
                    {
                        MailerSenderBookCollection = mailerSenderBookCollection,
                    });
                }
                LogTo.Info($"copy tddb success.");
            }
            catch
            {
                LogTo.Error("send mail error");
                _historyTestDirectorDatabaseStore.RemoveLastest();
                throw;
            }
        }

        public void Execute(IJobExecutionContext context)
        {
            Notificat();
        }

        public TimeSpan ActTime { get; } = TimeSpan.FromMinutes(30);
        public string CronExpression => _systemOptions.MailJobCronExpression;
    }
}
